/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package br.ufrn.engcomp.pds.helloopc.modelo.negocio.opc;

import java.util.SortedMap;
import java.util.TreeMap;
import javafish.clients.opc.*;
import javafish.clients.opc.component.OpcGroup;
import javafish.clients.opc.component.OpcItem;
import javafish.clients.opc.exception.ConnectivityException;
import javafish.clients.opc.exception.SynchReadException;
import javafish.clients.opc.exception.SynchWriteException;
import javafish.clients.opc.exception.UnableAddGroupException;
import javafish.clients.opc.exception.UnableAddItemException;
import javafish.clients.opc.variant.Variant;

/**
 *
 * @author ufrn
 */
public class ConexaoOPC /*implements Comparable<OPCUtil>*/ {

    /** Nome do cadastro de um servidor OPC */
    private int id;
    private String host;
    private String serverName;
    private boolean conectado;

    private JEasyOpc jopc;
    private OpcGroup grupoPadrao;
    private SortedMap<String, OpcItem> variaveis;

    private static ConexaoOPC currentInstance;

    public String getHost() {
        return host;
    }

    public void setHost(String host) {
        this.host = host;
    }

    static {
        // Inicializa a biblioteca JEasyOPC
        JEasyOpc.coInitialize();
    }

    /**
     * Finaliza a biblioteca JEasyOPC.
     * Deve ser chamado no fim da execução do programa.
     */
    public static void finalizar() {
        JEasyOpc.coUninitialize();
    }

    private ConexaoOPC(String host, String serverName, int id) {
        this.id = id;
        this.host = host;
        this.serverName = serverName;
        this.conectado = false;

        this.jopc = new JEasyOpc(host, serverName, "JOPC" + Math.random());
        grupoPadrao = new OpcGroup("grupo", true, 100, 0f);
        variaveis = new TreeMap<String, OpcItem>();
    }

    /**
     * Conecta ao servidor OPC e executa o cliente.
     * @param jopc
     */
    public void conectar() throws OPCException {
        try {
            if (jopc.getGroupsAsArray().length > 0) {
                jopc.removeGroup(grupoPadrao);
            }

            jopc.addGroup(grupoPadrao);
            jopc.connect();
            jopc.registerGroups();

            conectado = true;
        } catch (UnableAddItemException e) {
            e.printStackTrace();

            throw new OPCException("Não foi possível adicionar alguns itens ao grupo.");
        } catch (UnableAddGroupException e) {
            e.printStackTrace();

            throw new OPCException("Não foi possível adicionar o grupo.");
        } catch (ConnectivityException e) {
            e.printStackTrace();

            throw new OPCException("Não foi possível se conectar ao servidor.");
        }
    }

    public void desconectar() {
        jopc.terminate();

        currentInstance = null;
    }

    @Override
    public void finalize() {
        if (jopc.isRunning())
            desconectar();
    }

    public void addVariavel(String nome) {
        if (variaveis.containsKey(nome))
            return;
        OpcItem var = new OpcItem(nome, true, "");
        grupoPadrao.addItem(var);
        variaveis.put(nome, var);
    }

    public double getVariavel(String nome) {
        OpcItem response = null;
        try {
            response = jopc.synchReadItem(grupoPadrao, variaveis.get(nome));
        } catch (SynchReadException e) {
            e.printStackTrace();
        }
        return Double.parseDouble(response.getValue().toString());
    }

    public void setVariavel(String nome, double valor) {
        OpcItem item = variaveis.get(nome);
        item.setValue(new Variant(valor));
        try {
            jopc.synchWriteItem(grupoPadrao, item);
        } catch (SynchWriteException e) {
            e.printStackTrace();
        }
    }

    /*public int compareTo(ConexaoOPC that) {
        return this.getServerName().compareTo(that.getServerName());
    }*/

    public String getServerName() {
        return serverName;
    }

    public static ConexaoOPC newInstance(String host, String serverName, int handle) {
        currentInstance = new ConexaoOPC(host, serverName, handle);

        return currentInstance;
    }

    public static ConexaoOPC getCurrentInstance() {
        return currentInstance;
    }

    public boolean isInstance(String host, String serverName) {
        return host.equals(currentInstance.getHost()) && serverName.equals(currentInstance.getServerName());
    }

    public boolean isRunning() {
        return jopc.isRunning();
    }

    public static boolean isConnected() {
        return currentInstance != null && currentInstance.conectado;
    }

    public int getId() {
        return id;
    }

}